package com.xiguanlezz.cn.server;

import com.xiguanlezz.cn.ProviderReflectConst;
import com.xiguanlezz.cn.ScannerConst;
import com.xiguanlezz.cn.ThreadPoolUtils;
import com.xiguanlezz.cn.protocol.*;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastMethod;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;

/**
 * @Author：习惯了种种
 * @CreateDate：2024/11/3 14:35
 * @Description：
 */
@Slf4j
public class RpcProviderHandler extends SimpleChannelInboundHandler<RpcProtocol<RpcRequest>> {
    private Map<String, Object> handlerMap;
    @Setter
    private String reflectType = "jdk";

    public RpcProviderHandler(Map<String, Object> handlerMap) {
        this.handlerMap = handlerMap;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RpcProtocol<RpcRequest> rpcRequestRpcProtocol) throws Exception {
        Runnable task = new Runnable() {
            @Override
            public void run() {
                RpcHeader rpcHeader = rpcRequestRpcProtocol.getHeader();
                RpcRequest body = rpcRequestRpcProtocol.getBody();
                if (Objects.isNull(rpcHeader) || Objects.isNull(body)) {
                    return;
                }

                RpcResponse rpcBody = null;
                // 反射调用对应的服务方法
                Object result = null;
                try {
                    result = invokeServiceMethod(reflectType, body);
                    rpcHeader.setMessageStatus(RpcMessageStatus.SUCCESS.getStatus());
                    rpcBody = RpcResponse.builder()
                            .result(result)
                            .invokeMethodType(body.getInvokeMethodType())
                            .build();
                } catch (Throwable e) {
                    // 设置错误消息
                    rpcHeader.setMessageStatus(RpcMessageStatus.ERROR.getStatus());
                    rpcBody = RpcResponse.builder()
                            .error(e.toString())
                            .invokeMethodType(body.getInvokeMethodType())
                            .build();
                }

                // 将类型设置为响应消息
                rpcHeader.setMessageType(RpcMessageType.RESPONSE.getType());
                RpcProtocol<RpcResponse> responseRpcProtocol = new RpcProtocol<>(rpcHeader, rpcBody);
                ctx.writeAndFlush(responseRpcProtocol).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture channelFuture) throws Exception {
                        log.info("provider sends msg successfully！");
                    }
                });
            }
        };
        ThreadPoolUtils.submit(task);
    }

    private Object invokeServiceMethod(String reflectType, RpcRequest request) throws Throwable {
        // 先找到要调用的service对象
        String key = String.format(ScannerConst.SERVICE_KEY_FORMAT, request.getClassName(), request.getVersion(), request.getGroup());
        Object serviceObj = handlerMap.get(key);
        if (Objects.isNull(serviceObj)) {
            throw new RuntimeException(String.format("service: %s#%s not exists...", request.getClassName(), request.getMethodName()));
        }

        Class<?> clazz = serviceObj.getClass();
        String methodName = request.getMethodName();
        Class<?>[] paramTypes = request.getParamTypes();
        Object[] params = request.getParams();
        switch (reflectType) {
            case ProviderReflectConst.REFLECT_TYPE_JDK:
                // JDK调用
                return invokeJdkMethod(serviceObj, clazz, methodName, paramTypes, params);
            case ProviderReflectConst.REFLECT_TYPE_CGLIB:
                // Cglib调用
                return invokeCglibMethod(serviceObj, clazz, methodName, paramTypes, params);
            default:
                return null;
        }
    }

    private Object invokeJdkMethod(Object serviceObj, Class<?> serviceClazz, String methodName,
                                   Class<?>[] paramTypes, Object[] params) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        // 找到服务方法
        Method method = serviceClazz.getMethod(methodName, paramTypes);
        method.setAccessible(true);
        // 开始反射调用对应的服务方法
        return method.invoke(serviceObj, params);
    }

    private Object invokeCglibMethod(Object serviceObj, Class<?> serviceClazz, String methodName,
                                     Class<?>[] paramTypes, Object[] params) throws InvocationTargetException {
        FastClass serviceFastClass = FastClass.create(serviceClazz);
        FastMethod serviceFastMethod = serviceFastClass.getMethod(methodName, paramTypes);
        return serviceFastMethod.invoke(serviceObj, params);
    }

//    @Override
//    protected void channelRead0(ChannelHandlerContext ctx, Object o) throws Exception {
//        log.info("rpc provider has received msg: {} ======== handlerMap: {}", o, handlerMap);
//    }
}
